<?php

namespace helper;

class Form
{

  /**
   * 生成文本框(按类型)
   * @param $type
   * @param $name
   * @param $value
   * @param array $options
   * @return string
   */
  static public function _input($type, $name, $value, $options = [])
  {
    if (!isset($options['name'])) $options['name'] = $name; //补充name属性
    $options['class'] = isset($options['class']) //补充name属性
        ? $options['class'] . (stripos($options['class'], 'form-control') !== false ? '' : ' form-control')
        : 'form-control';
    if (!in_array($type, ['checkbox', 'radio'])) {
      $options['value'] = $value;
    }
    $options['type'] = $type;
    return '<input' . self::attributes($options) . ' />';
  }

  /**
   * 生成普通文本框
   * @param string $name
   * @param string $value
   * @param array $options
   * @return string
   */
  static public function _text($name, $value, $options = [])
  {
    return self::_input('text', $name, $value, $options);
  }

  /**
   * 生成密码文本框
   * @param string $name
   * @param string $value
   * @param array $options
   * @return string
   */
  static public function _password($name, $value, $options = [])
  {

    return self::_input('password', $name, $value, $options);
  }

  /**
   * 生成隐藏文本框
   * @param string $name
   * @param string $value
   * @param array $options
   * @return string
   */
  static public function _hidden($name, $value, $options = [])
  {
    return self::_input('hidden', $name, $value, $options);
  }

  /**
   * 日期选择器
   * @param string $name
   * @param mixed $value
   * @param array $options
   * @return string
   */
  static public function _laydate($name, $value, $options = [])
  {
    if (empty($value)) $value = '';
    if (is_numeric($value) && strlen($value) === 10) {
      $dateFormat = [
          'yyyy' => 'Y',
          'MM' => 'm',
          'dd' => 'd',
          'HH' => 'H',
          'mm' => 'i',
          'ss' => 's',
      ];
      $format     = 'Y-m-d';
      if (isset($options['data-format'])) {
        $format = str_replace(array_keys($dateFormat), array_values($dateFormat), $options['data-format']);
      }
      $value = date($format, $value);
    }
    $options['class'] = isset($options['class']) ? 'form-control f-laydate ' . $options['class'] : 'form-control f-laydate';
    return self::_input('text', $name, $value, $options);
  }

  /**
   * 生成数字框
   * @param string $name
   * @param string $value
   * @param array $options
   * @return string
   */
  static public function _number($name, $value, $options = [])
  {
    if (!isset($options['data-type'])) $options['data-type'] = 'float';
    $options['class'] = isset($options['class']) ? 'form-control f-number' . $options['class'] : 'form-control f-number';
    return self::_input('text', $name, $value, $options);
  }

  /**
   * 生成多行文本框
   * @param string $name
   * @param string $value
   * @param array $options
   * @return string
   */
  static public function _textarea($name, $value, $options = [])
  {
    if (!isset($options['name'])) $options['name'] = $name;
    if (!isset($options['rows'])) $options['rows'] = 3;
    $value            = Utils::htmlOut($value);
    $options['class'] = isset($options['class']) ? $options['class'] . (stripos($options['class'], 'form-control') !== false ? '' : ' form-control') : 'form-control';
    $options          = self::attributes($options);
    return '<div class="form-control-static"><textarea' . $options . '>' . $value . '</textarea></div>';
  }

  /**
   * switch开关
   * @param $name
   * @param $value
   * @param array $options
   * @return string
   */
  static public function _switch($name, $value, $options = [])
  {
    $themeCss = isset($options['theme-css']) ? $options['theme-css'] : 'switch-solid switch-primary';
    if (!isset($options['name'])) $options['name'] = $name;
    $options['value'] = 1;
    $options          = self::attributes($options);
    $checked          = $value == '1' ? 'checked' : '';
    $h                = <<<EOT
<div class="form-control-static">
<label class="switch {$themeCss}">
      <input type="checkbox" {$options} $checked />
      <span></span>
</label>
</div>
EOT;
    return $h;
  }

  /**
   * tags标签框
   * @param $name
   * @param $value
   * @param array $options
   * @return string
   */
  static public function _tags($name, $value, $options = [])
  {
    $options['class'] = isset($options['class']) ? 'f-tags' . $options['class'] : 'f-tags';
    return self::_input('text', $name, $value, $options);
  }

  /**
   * 富文本编辑器
   * @param $name
   * @param $value
   * @param array $options
   * @return string
   */
  static public function _ckeditor($name, $value, $options = [])
  {
    $options['class'] = isset($options['class']) ? 'f-ck-editor ' . $options['class'] : 'f-ck-editor';
    $value            = Utils::htmlOut($value);
    return '<div class="form-control-static">' . self::_textarea($name, $value, $options) . '</div>';
  }

  /**
   * 生成代码编辑器
   * @param $name
   * @param $value
   * @param array $options
   * @return string
   */
  static public function _ace($name, $value, $options = [])
  {
    $options['id']        = $name;
    $options['class']     = isset($options['class']) ? ' f-ace' . $options['class'] : 'f-ace';
    $options['data-mode'] = isset($options['data-mode']) ? $options['data-mode'] : 'html';
    $options              = self::attributes($options);
    $value                = Utils::htmlOut($value);
    $h                    = <<<EOT
<textarea name="{$name}" class="hidden">{$value}</textarea>
<pre {$options}>{$value}</pre>
EOT;
    return $h;
  }

  /**
   * 省市区选择
   * @param $name
   * @param $value
   * @param array $options
   * @return string
   */
  static public function _area($name, $value, $options = [])
  {
    $options = self::attributes($options);
    $h       = <<<EOT
<div class="f-area" data-name="{$name}" {$options}>
    <input type="hidden" name="{$name}" value="{$value}" />
    <select class="form-control prov"></select>
    <select class="form-control city"></select>
    <select class="form-control area"></select>
</div>
EOT;
    return $h;
  }


  /**
   * 生成下拉列表框
   * @param string $name
   * @param mixed $value
   * @param array $options
   * @return string
   */
  static public function _select($name, $value, $options = [])
  {
    if (!isset($options['items-data'])) return '数据源不能为空！';
    if (!isset($options['items-key'])) $options['items-key'] = 'key';
    if (!isset($options['items-name'])) $options['items-name'] = 'name';
    if (!isset($options['name'])) $options['name'] = $name;
    $options['class'] = isset($options['class'])
        ? $options['class'] . (stripos($options['class'], 'form-control') !== false ? '' : ' form-control')
        : 'form-control';
    $html             = [];
    if (isset($options['empty-option'])) {
      $emptyOption = explode('|', $options['empty-option']);
      $html[]      = '<option value="' . $emptyOption[0] . '">' . $emptyOption[1] . '</option>';
    }
    $list     = self::getListData($options['items-data']);
    $multiple = isset($options['multiple']) ? true : false;
    if (!empty($list)) {
      foreach ($list as $k => $v) {
        if ($multiple === true) {
          $arr = $value;
          if (is_string($value)) {
            $arr = empty($value) ? [] : explode(',', $value);
          }
          $selectedHtml = (in_array($v[$options['items-key']], $arr)) ? 'selected' : '';
        } else {
          $selectedHtml = ($v[$options['items-key']] == $value) ? 'selected' : '';
        }
        $disabledHtml = isset($v['disabled']) ? $v['disabled'] : '';
        $html[]       = '<option value="' . $v[$options['items-key']] . '" ' . $selectedHtml . ' ' . $disabledHtml . '>' . $v[$options['items-name']] . '</option>';
      }
    }
    $options = self::attributes($options);
    $list    = implode(PHP_EOL, $html);
    return "<select {$options}>{$list}</select>";
  }

  /**
   * 生成复选框
   * @param string $name
   * @param mixed $value
   * @param array $options
   * @return string
   */
  static public function _checkbox($name, $value, $options = [])
  {
    if (!isset($options['items-data'])) return '数据源不能为空！';
    if (!isset($options['items-key'])) $options['items-key'] = 'key';
    if (!isset($options['items-name'])) $options['items-name'] = 'name';
    $themeCss  = isset($options['theme-css']) ? $options['theme-css'] : 'checkbox-primary';
    $itemsKey  = $options['items-key']; //键
    $itemsName = $options['items-name']; //显示值
    $html      = [];
    $list      = self::getListData($options['items-data']);
    if (!empty($list)) {
      $options = self::attributes($options);
      foreach ($list as $k => $v) {
        $checked = in_array($v[$itemsKey], explode(',', $value)) ? 'checked' : '';
        $html[]  = <<<EOT
<label class="checkbox checkbox-inline {$themeCss}">
    <input type="checkbox" {$options} name="{$name}[]" value="{$v[$itemsKey]}" {$checked} /><span>{$v[$itemsName]}</span>
</label>
EOT;
      }
    }
    return implode(PHP_EOL, $html);
  }

  /**
   * 生成单选框
   * @param string $name
   * @param mixed $value
   * @param array $options
   * @return string
   */
  static public function _radio($name, $value, $options = [])
  {
    if (!isset($options['items-data'])) return '数据源不能为空！';
    if (!isset($options['items-key'])) $options['items-key'] = 'key';
    if (!isset($options['items-name'])) $options['items-name'] = 'name';
    $themeCss  = isset($options['theme-css']) ? $options['theme-css'] : 'radio-primary';
    $itemsKey  = $options['items-key']; //键
    $itemsName = $options['items-name']; //显示值
    $html      = [];
    $list      = self::getListData($options['items-data']);
    if (!empty($list)) {
      $options = self::attributes($options);
      foreach ($list as $k => $v) {
        $checked = $v[$itemsKey] == $value ? 'checked' : '';
        $html[]  = <<<EOT
<label class="radio radio-inline {$themeCss}">
    <input type="radio" {$options} name="{$name}" value="{$v[$itemsKey]}" {$checked} /><span>{$v[$itemsName]}</span>
</label>
EOT;
      }
    }
    return implode(PHP_EOL, $html);
  }

  /**
   * selectPage控件
   * @param $name
   * @param $value
   * @param array $options
   * @return string
   */
  static public function _selectPage($name, $value, $options = [])
  {
    if (!isset($options['name'])) $options['name'] = $name; //补充name属性
    $options['class'] = isset($options['class']) ? $options['class'] : 'form-control f-selectPage';
    $options['value'] = $value;
    $options          = self::attributes($options);
    $h                = <<<EOT
<input type="text" {$options} />
EOT;
    return $h;
  }

  /**
   * 项目列表
   * @param $name
   * @param $value
   * @param array $options data-files=[]
   * @return string
   * @throws \Exception
   */
  static public function _inputGroup($name, $value, $options = [])
  {
    $files = $options['data-files'];
    $value = !empty($value) ? json_decode($value, true) : [];
    $thead = '';
    $item  = '';
    foreach ($files as $k => $v) {
      $thead .= <<<EOT
        <th style="width:{$v['width']}">{$v['name']}</th>
EOT;
    }
    $thead .= '<th style="width:160px">操作</th>';
    if (empty($value)) {
      $item .= ' <tr class="item">';
      foreach ($files as $k => $v) {
        $inputOption = '';
        if (isset($v['inputOptions'])) $inputOption = self::attributes($v['inputOptions']);
        $item .= <<<EOT
        <td>
            <input type="text" class='form-control item-input' data-name="{$k}" {$inputOption}>
        </td>
EOT;
      }
      $item .= <<<EOT
        <td>
            <a href="javascript:;" onclick="formHelper.inputGroupAdd(this)" class="btn btn-info btn-add"><i class="mdi mdi-plus"></i></a>
            <a href="javascript:;" onclick="formHelper.inputGroupDel(this)" class="btn btn-danger btn-del"><i class="mdi mdi-delete"></i> </a>
            <a href="javascript:;" onclick="formHelper.inputGroupup(this)" class="btn btn-default btn-up"><i class="mdi mdi-arrow-up"></i> </a>
            <a href="javascript:;" onclick="formHelper.inputGroupdown(this)" class="btn btn-default btn-down"><i class="mdi mdi-arrow-down"></i> </a>
        </td>
</tr>
EOT;
    } else {
      foreach ($value as $k => $v) {
        $row = '<tr class="item">';
        foreach ($files as $kk => $vv) {
          $inputOption = '';
          if (isset($vv['inputOptions'])) {
            $inputOption = self::attributes($vv['inputOptions']);
          }
          $row .= <<<EOT
        <td>
            <input type="text" class='form-control item-input' data-name="{$kk}" value="$v[$kk]" {$inputOption}>
        </td>
EOT;
        }
        $row    .= <<<EOT
        <td>
            <a href="javascript:;" onclick="formHelper.inputGroupAdd(this)" class="btn btn-info btn-add"><i class="mdi mdi-plus"></i></a>
            <a href="javascript:;" onclick="formHelper.inputGroupDel(this)" class="btn btn-danger btn-del"><i class="mdi mdi-delete"></i> </a>
            <a href="javascript:;" onclick="formHelper.inputGroupup(this)" class="btn btn-default btn-up"><i class="mdi mdi-arrow-up"></i> </a>
            <a href="javascript:;" onclick="formHelper.inputGroupdown(this)" class="btn btn-default btn-down"><i class="mdi mdi-arrow-down"></i> </a>
        </td>
</tr>
EOT;
        $rows[] = $row;
      }
      $item = implode(PHP_EOL, $rows);
    }
    $h = <<<EOT
<table class="table f-input-group" data-name="{$name}">
   <thead>
        <tr>
           {$thead}
        </tr>
    </thead>
        {$item}
</table>
EOT;
    return $h;
  }

  /**
   * 图片上传
   * @param $name
   * @param $value
   * @param array $options
   * @return string
   * @throws \Exception
   */
  static public function _uploadImage($name, $value, $options = [])
  {
    $theme   = isset($options['data-theme']) ? $options['data-theme'] : 'single01';
    $options = self::attributes($options);
    switch ($theme) {
      case 'single01':
        $val = get_attachment_json($value, 1);
        break;
      case 'single02':
        $val = $value;
        break;
    }
    return <<<EOT
<div class="input-group f-upload" {$options} data-type="image" data-theme="{$theme}" data-name='{$name}' data-value='{$val}'>
    <input class="hide" type="file" accept="image/*" /> 
    <input type="text" class="form-control file-url" name="{$name}" value="" />
    <span class="input-group-btn">
        <button class="btn btn-default upload-btn" type="button"><i class="mdi mdi-file-image"></i> 上传</button>
    </span>
    <span class="input-group-btn">
        <button class="btn btn-default" type="button" data-type="single" data-file="image" onclick="themeCallfn.selectFile(this);"><i class="mdi mdi-select"></i> 选择图片</button>
    </span>
    <span class="input-group-btn">
        <button class="btn btn-default" type="button" onclick="themeCallfn.singleShow(this)"><i class="mdi mdi-eye"></i> 预览</button>
    </span>
    <span class="input-group-btn">
        <button class="btn btn-default" type="button" onclick="themeCallfn.single01Del(this)"><i class="mdi mdi-delete"></i> 删除</button>
    </span>
</div>
EOT;
  }

  /**
   * 多图上传
   * @param $name
   * @param $value
   * @param array $options
   * @return string
   * @throws \Exception
   */
  static public function _uploadImages($name, $value, $options = [])
  {
    $theme   = $options['data-theme'];
    $options = self::attributes($options);
    switch ($theme) {
      case 'multi01':
        $json = get_attachment_json($value, 2);
        break;
      default: //默认取带描述场景
        $json = get_attachment_json($value, 3);
        break;
    }
    return <<<EOT
<div class="f-upload" {$options} data-type="image" data-theme="{$theme}" data-theme-fun="multi" data-name="{$name}" data-value='{$json}'>
    <input class="hide" type="file" accept="image/*" multiple/>
    <button type="button" class="btn btn-default upload-btn">
        <i class="mdi mdi-upload"></i> 上传图片
    </button>
    <button type="button" class="btn btn-default" data-type="multi" data-file="image" onclick="themeCallfn.selectFile(this);">
        <i class="mdi mdi-select"></i> 选择图片
    </button>
    <ul class="upload-list upload-{$theme}-list"></ul>
</div>
EOT;
  }

  /**
   * 多附件上传
   * @param $name
   * @param $value
   * @param array $options
   * @return string
   * @throws \Exception
   */
  static public function _uploadFiles($name, $value, $options = [])
  {
    $theme   = $options['data-theme'];
    $options = self::attributes($options);
    $json    = get_attachment_json($value, 3);
    return <<<EOT
<div class="f-upload" {$options} data-type="file" data-theme="{$theme}" data-theme-fun="multi" data-name="{$name}" data-value='{$json}'>
<input class="hide" type="file" multiple/>
<button type="button" class="btn btn-default upload-btn">
<i class="mdi mdi-upload"></i> 上传附件
</button>
<button type="button" class="btn btn-default" data-type="multi" onclick="themeCallfn.selectFile(this);">
<i class="mdi mdi-select"></i> 选择附件
</button>
<div style="height:10px;"></div>
<ul class="upload-list upload-{$theme}-list"></ul>
</div>
EOT;
  }

  /**
   * 附件上传
   * @param $name
   * @param $value
   * @param array $options
   * @return string
   * @throws \Exception
   */
  static public function _uploadFile($name, $value, $options = [])
  {
    $theme   = $options['data-theme'];
    $options = self::attributes($options);
    $h       = '';
    switch ($theme) {
      case 'single01':
        $json = get_attachment_json($value, 1);
        $h    = <<<EOT
<div class="input-group f-upload" {$options} data-type="file" data-theme="single01" data-name='{$name}' data-value='{$json}'>
    <input class="hide" type="file" /> 
    <input type="text" class="form-control file-url" name="{$name}" value="" />
    <span class="input-group-btn">
        <button class="btn btn-default upload-btn" type="button"><i class="mdi mdi-file-image"></i> 上传</button>
    </span>
    <span class="input-group-btn">
        <button class="btn btn-default" type="button" data-type="single" data-file="doc,docx,wps,xls,xlsx,csv,ppt,pptx,txt,md,jpg,jpeg,png,gif,bmp,mp3,MP4,mov,zip,rar,tar,gzip,gz,7z, WebM, Ogv,webp" onclick="themeCallfn.selectFile(this);"><i class="mdi mdi-select"></i> 选择附件</button>
    </span>
    <span class="input-group-btn">
        <button class="btn btn-default" type="button" onclick="themeCallfn.single01Del(this)"><i class="mdi mdi-delete"></i> 删除</button>
    </span>
</div>
EOT;
        break;
    }
    return $h;
  }

  /*
   * 数组转换字符串
   * @param  array $options
   * @return string
   */
  static protected function attributes($options)
  {
    $html = [];
    foreach ((array)$options as $key => $value) {
      if (is_numeric($key)) $key = $value;
      $element = self::attributeElement($key, $value);
      if (!is_null($element)) $html[] = $element;
    }
    return count($html) > 0 ? ' ' . implode(' ', $html) : '';
  }

  /**
   * 拼接属性
   * @param $key
   * @param $value
   * @return string|null
   */
  static protected function attributeElement($key, $value)
  {
    if (in_array($key, ['theme-css', 'items-data', 'items-key', 'items-name', 'empty-option', 'upload'])) return null;
    if (!is_null($value)) {
      if (is_array($value) || stripos($value, '"') !== false) {
        $value = is_array($value) ? json_encode($value, JSON_UNESCAPED_UNICODE) : $value;
        return $key . "='" . $value . "'";
      } else {
        return $key . '="' . $value . '"';
      }
    }
  }

  /**
   * 解析传入数据
   * @param string $listData
   * @return array|mixed
   */
  static public function getListData($listData)
  {
    if (is_string($listData)) {
      $listData = explode(":", (string)$listData);
      $list     = [];
      switch ($listData[0]) {
        case 'url': //调用url回调 url:数据源地址
          $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
          $data     = http::get($protocol . $_SERVER['HTTP_HOST'] . $listData[1]);
          $list     = json_decode($data, true);
          $list     = is_array($list) ? $list : [];
          break;
        case 'fun': //执行指定方法 fun:方法名:参数1,参数2,参数3
          $fun    = $listData[1];
          $params = isset($listData[2]) ? explode(',', $listData[2]) : [];
          $list   = call_user_func_array($fun, $params);
          break;
        case 'class': //执行指定类方法 类路径需\\隔开 class:calss类名:方法名:参数1,参数2
          $class  = $listData[1];
          $fun    = $listData[2];
          $params = isset($listData[3]) ? explode(',', $listData[3]) : [];
          $list   = call_user_func_array([$class, $fun], $params);
          break;
        case 'D': //执行指定模型方法 模型路径:方法名:参数1,参数2,参数3
          $class  = $listData[1];
          $fun    = $listData[2];
          $params = isset($listData[3]) ? explode(',', $listData[3]) : [];
          $list   = call_user_func_array([D($class), $fun], $params);
          break;
        case 'static': //静态数据 1|男,2|女
          $arr  = explode(',', $listData[1]);
          $list = [];
          foreach ($arr as $v) {
            $item   = explode('|', $v);
            $list[] = ['key' => $item[0], 'name' => $item[1]];
          }
          break;
      }
    } else {
      if (is_object($listData)) $listData = $listData->isEmpty() ? [] : $listData->toArray(); //处理对象转数组
      $list = $listData;
    }
    return $list;
  }
}